#include "Task.h"
#include "ThreadPool.h"
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <memory>

using std::cout;
using std::endl;
using std::unique_ptr;

class MyTask
: public Task
{
public:
    void process() override
    {
       ::srand(::clock()) ;
       int number = ::rand()%100;
       cout << ">>>MyTask number = " << number << endl;
    }
};

//任务确实每次添加了20次，但是会出现如下两个问题？
//
//1、任务没有执行完毕，线程池就退出来？
//原因：因为主线程在添加任务，子线程（工作线程）在拿任务与执行
//任务，如果主线程添加完了20次任务之后，会继续向下执行，也就是
//会走到stop函数中，如果主线程很快的将标志位_isExit设置为了
//true,那么如果子线程在doTask中执行完任务之后，会继续拿任务
//但是需要走while循环，判断循环条件，如果此时发现循环条件
//不满足，也就是_isExit为true，那么子线程就会从doTask中退出
//也就是任务没有执行完毕，子线程也会退出
//解决方案:在主线程执行stop的时候，在将标志位_isExit设置为true
//之前，只要任务执行不完，就不向下执行_taskQue.empty()
//
//2、任务执行完毕了，但是线程池没有退出来？
//原因:如果子线程在执行doTask的时候，将最后的任务通过getTask
//获取完毕之后，也就是说任务队列为空了，那么此时有两种可能
//(1)如果主线程抢夺了CPU的控制权，跑的快一些，那么会将标志为
//_isExit设置为true,子线程继续执行process函数，执行完毕之后
//继续走while循环，发现条件已经不满足了，就可以退出doTask，
//此时主线程可以回收子线程;
//(2)如果子线程抢夺了CPU的控制权，跑的快一些，执行process函数
//并且继续判断while中的循环条件,发现标志位_isExit还是false，
//那么会继续执行getTask函数，但是发现已经没有任务可以进行获取
//了，所以此时子线程会睡眠，那么即使主线程再将标志位_isExit
//设置为true也已经没有作用了，那么子线程处于睡眠状态,就不能
//回收子线程了
//
//解决方案:第一种解决方案：就是让子线程每执行一次任务就睡眠
//一会，这样可以保证主线程比子线程跑得快，就可以回收子线程
//这样方式不大好；
//第二种解决方法是：即使子线程跑的快，最终也会在_notEmpty
//条件变量上睡眠，只需要在主线程的stop中将所有等待的线程
//唤醒即可,添加了wakeup函数

void test()
{
    unique_ptr<Task> ptask(new MyTask());

    ThreadPool pool(4, 10);
    //启动线程池
    pool.start();
    //需要在启动线程池之后，要添加任务
    int cnt = 20;
    while(cnt--)
    {
        pool.addTask(ptask.get());
        cout << "cnt = " << cnt << endl;
    }
    //当任务执行完毕之后，可以让线程池退出
    pool.stop();
}

int main(int argc, char *argv[])
{
    test();
    return 0;
}

